/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * TSPGUI.java
 *
 * Created on 11.mar.2011, 21:28:46
 */
package travelingsalesman;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.SwingWorker;

/**
 *
 * @author Rex Boris
 * @author DiaAWAY
 */
public class TSPGUI extends javax.swing.JFrame {

    public static final Logger log = Logger.getLogger(Main.class.getName());
    private String[] files = {"wi29.tsp", "dj38.tsp", "qa194.tsp"};
    private String currentFile = "wi29.tsp"; // same as first element in files
    private String previousFile = currentFile;
    private SelfOMapTSP SOM = null;
    private CitiesFromFileReader cffr = new CitiesFromFileReader();
    private double[][] dat = null;
    public static int FPS = 30;
    private static boolean update = true;

    /** Creates new form TSPGUI */
    public TSPGUI() {
        initComponents();
        startUpdate();
    }

    private void startUpdate() {
        Thread t = new Thread(new Runnable() {

            public void run() {
                while (true) {
                    try {
                        if (update) {
                            repaint();
                        }
                        synchronized (this) {
                            this.wait(1000 / TSPGUI.FPS);
                        }
                    } catch (InterruptedException ex) {
                        Logger.getLogger(TSPGUI.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }
        });
        t.start();
    }

    public void loadFile() {
        try {
            dat = cffr.getDat(cffr.DataLocation + currentFile);
        } catch (NullPointerException ex) {
            log.log(Level.SEVERE, null, ex);
        } catch (FileNotFoundException ex) {
            log.log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            log.log(Level.SEVERE, null, ex);
        }
    }

    public void loadData() {
        if (dat != null) {
            log.log(Level.INFO, "Number of cities: {0}", dat.length);
//            SOM = new SelfOMapTSP(dat);
            SOM = new SelfOMapTSP(
                    Integer.parseInt(neighDeltaField.getText()), // d neighbourhood
                    Integer.parseInt(neuralMapSizeField.getText()), // M - neural map size
                    Integer.parseInt(neighBufferField.getText()), // d neighbour
                    Integer.parseInt(d_etaField.getText()), // d eta
                    dat,
                    this);
//            SOM.updateInterval = 10;
            ((Graph) graphPanel).setCities(SOM.input); // input is the normalized city coordinates
            SOM.execute();
            this.repaint();
            log.info("loading, init, start SOM");
        } else {
            log.severe("DATA FROM CitiesFromFileReader IS NULL");
        }
    }

    public void addToGraph(double[][] intermediate) {
        ((Graph)graphPanel).addWeights(intermediate);
    }

    public void updateDistance(double distance) {
        totalDistance.setText(""+distance);
    }

    public void updateMaxCount(int maxCount) {
        ((Graph)graphPanel).updateMaxCount(maxCount);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        graphPanel = new Graph();
        neighBufferField = new javax.swing.JTextField();
        neighBufferLabel = new javax.swing.JLabel();
        startButton = new javax.swing.JButton();
        neighDeltaLabel = new javax.swing.JLabel();
        neighDeltaField = new javax.swing.JTextField();
        d_etaLabel = new javax.swing.JLabel();
        d_etaField = new javax.swing.JTextField();
        fileSelector = new javax.swing.JComboBox();
        stopButton = new javax.swing.JButton();
        pauseButton = new javax.swing.JToggleButton();
        totalDistanceLabel = new javax.swing.JLabel();
        totalDistance = new javax.swing.JLabel();
        neuralMapSizeLabel = new javax.swing.JLabel();
        neuralMapSizeField = new javax.swing.JTextField();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Traveling salesman");
        setLocationByPlatform(true);
        setResizable(false);

        graphPanel.setBackground(new java.awt.Color(255, 255, 255));
        graphPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
        graphPanel.setMaximumSize(new java.awt.Dimension(500, 500));
        graphPanel.setMinimumSize(new java.awt.Dimension(500, 500));
        graphPanel.setPreferredSize(new java.awt.Dimension(500, 500));

        javax.swing.GroupLayout graphPanelLayout = new javax.swing.GroupLayout(graphPanel);
        graphPanel.setLayout(graphPanelLayout);
        graphPanelLayout.setHorizontalGroup(
            graphPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 496, Short.MAX_VALUE)
        );
        graphPanelLayout.setVerticalGroup(
            graphPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 496, Short.MAX_VALUE)
        );

        neighBufferField.setText("50");

        neighBufferLabel.setText("Neighbourhood Buffer");

        startButton.setText("Start");
        startButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                startButtonActionPerformed(evt);
            }
        });

        neighDeltaLabel.setText("Neighbourhood Delta");

        neighDeltaField.setText("1");

        d_etaLabel.setText("Initial learning rate");

        d_etaField.setText("1");

        fileSelector.setModel(new javax.swing.DefaultComboBoxModel(files));
        fileSelector.addItemListener(new java.awt.event.ItemListener() {
            public void itemStateChanged(java.awt.event.ItemEvent evt) {
                fileSelectorItemStateChanged(evt);
            }
        });

        stopButton.setText("Stop");
        stopButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                stopButtonActionPerformed(evt);
            }
        });

        pauseButton.setText("Pause");
        pauseButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                pauseButtonActionPerformed(evt);
            }
        });

        totalDistanceLabel.setText("Total distance:");

        totalDistance.setText("0");

        neuralMapSizeLabel.setText("Neural map size");

        neuralMapSizeField.setText("150");

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                    .addComponent(d_etaField)
                    .addComponent(neighDeltaField)
                    .addComponent(neighBufferField)
                    .addComponent(fileSelector, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(pauseButton, 0, 0, Short.MAX_VALUE)
                    .addComponent(stopButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(totalDistance, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(neuralMapSizeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(neuralMapSizeField)
                    .addComponent(startButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(totalDistanceLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(neighDeltaLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(neighBufferLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(d_etaLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addGap(18, 18, 18)
                .addComponent(graphPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(fileSelector, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(47, 47, 47)
                        .addComponent(neighBufferLabel)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(neighBufferField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(18, 18, 18)
                        .addComponent(neighDeltaLabel)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(neighDeltaField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(18, 18, 18)
                        .addComponent(d_etaLabel)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(d_etaField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(18, 18, 18)
                        .addComponent(neuralMapSizeLabel)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(neuralMapSizeField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(totalDistanceLabel)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(totalDistance)
                        .addGap(18, 18, 18)
                        .addComponent(startButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(pauseButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(stopButton))
                    .addComponent(graphPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap())
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void startButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_startButtonActionPerformed
        stopButtonActionPerformed(evt); // herp derp
        ((Graph) graphPanel).stop(); // clear the graph
        if (SOM == null) { // initialize
            loadFile();
            loadData();
            log.info("starting SOM");
        } else {
            log.warning("cannot start SOM when it is running");
        }
    }//GEN-LAST:event_startButtonActionPerformed

    private void fileSelectorItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_fileSelectorItemStateChanged
        if (evt.getStateChange() == evt.SELECTED) {
            previousFile = (String) fileSelector.getSelectedItem();
        }
        if (evt.getStateChange() == evt.DESELECTED) {
            currentFile = (String) fileSelector.getSelectedItem();
            System.out.println(previousFile + " -> " + currentFile);
        }
    }//GEN-LAST:event_fileSelectorItemStateChanged

    private void stopButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_stopButtonActionPerformed
        if (SOM != null) { // SOM INITIALIZED
            SOM.isRunning = false;
            SOM.cancel(true);
            this.SOM = null;
            log.info("stopping SOM");
        } else {
            log.warning("cannot stop SOM when it is not running");
        }
        ((Graph) graphPanel).stop();
    }//GEN-LAST:event_stopButtonActionPerformed

    private void pauseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pauseButtonActionPerformed
        if (pauseButton.isSelected()) {
            ((Graph) graphPanel).isPausing = true;
            log.info("pause GRAPH drawing");
        } else {
            ((Graph) graphPanel).isPausing = false;
            log.info("start GRAPH drawing");
        }
    }//GEN-LAST:event_pauseButtonActionPerformed

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                new TSPGUI().setVisible(true);
            }
        });
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JTextField d_etaField;
    private javax.swing.JLabel d_etaLabel;
    private javax.swing.JComboBox fileSelector;
    private javax.swing.JPanel graphPanel;
    private javax.swing.JTextField neighBufferField;
    private javax.swing.JLabel neighBufferLabel;
    private javax.swing.JTextField neighDeltaField;
    private javax.swing.JLabel neighDeltaLabel;
    private javax.swing.JTextField neuralMapSizeField;
    private javax.swing.JLabel neuralMapSizeLabel;
    private javax.swing.JToggleButton pauseButton;
    private javax.swing.JButton startButton;
    private javax.swing.JButton stopButton;
    private javax.swing.JLabel totalDistance;
    private javax.swing.JLabel totalDistanceLabel;
    // End of variables declaration//GEN-END:variables
}
